#pragma once

#include <deque>
#include <stdint.h>
#include <boost/asio.hpp>
#include "tcp_message.h"
#include "subscriber.h"
#include "sessionmanager.h"
#include "messagehandler.h"
#include "app_common.h"

using TcpMessageQueue = std::deque<TcpMessage_t>;
using MessageType_t = std::map<std::string, int>;


class TcpServerSession
    : public Subscriber, public std::enable_shared_from_this<TcpServerSession>
{
public:
    TcpServerSession(boost::asio::io_context &io_context,
        SessionManager& ch,
        MessageType_t &messageTypes, ServerConfig_t& cfg);

    void writeTcpMessage(TcpMessage_t& msg);
    void writeTcpSessionMessage(TcpSessionMessage_t msg);
    void start();
    void close();

    boost::asio::ip::tcp::socket& socket()
    {
        return _socket;
    }
    boost::signals2::signal<void(TcpSessionMessage_t)> recvTcpMessageSignal;

    ServerConfig_t& serverConfig() { return _cfg; }
private:


    void startRead();
    void handleReadHeader(const boost::system::error_code& ec);
    void handleReadBody(const boost::system::error_code& ec);
    void doWrite(TcpMessage_t& msg);
    void startWrite(const TcpMessage_t& msg);
    void handleWrite(const boost::system::error_code& ec);
    void checkHeartbeat();
    void doClose();
    
private:

    bool _stopped = false;
    boost::asio::io_context& _io_context;
    boost::asio::ip::tcp::socket _socket;
    boost::asio::deadline_timer _heartbeatTimer;

    TcpMessage_t _readMsg;
    TcpMessageQueue _writeMsgs;

    bool _isRecvedHeartbeatReq = false;	// heart beat check flag

    uint32_t _heartBeatLostTimes = 0;

    std::string _rbuf;		// message bytes read buffer
    std::string _wbuf;		// message bytes write buffer

    MessageType_t& _messageTypes;
    SessionManager& _sessionManger;
    ServerConfig_t _cfg;
    std::string _sessionId;
};
